import platgo as pg
import numpy as np


class CF2(pg.Problem):

    def __init__(self, D: int = 10):
        self.name = "CF2"
        self.type['multi'], self.type['real'], self.type['large'], self.type['constrained'] = [True] * 4
        self.D = D
        self.M = 2
        lb = [0] + [-1] * (self.D - 1)
        ub = [1] * self.D
        self.borders = np.array([lb, ub])
        super().__init__()

    def cal_obj(self, pop: pg.Population) -> None:
        j1 = np.arange(2, self.D, 2)
        j2 = np.arange(1, self.D, 2)
        objv1 = pop.decs[:, 0] + 2 * np.mean((pop.decs[:, j1] -
                                              np.sin(6 * np.pi * pop.decs[:, 0].reshape(-1, 1) + (
                                                          j1 + 1) * np.pi / self.D)) ** 2, axis=1)
        objv2 = 1 - np.sqrt(pop.decs[:, 0]) + 2 * np.mean((pop.decs[:, j2] -
                                                           np.cos(6 * np.pi * pop.decs[:, 0].reshape(-1, 1) + (
                                                                       j2 + 1) * np.pi / self.D)) ** 2, axis=1)
        pop.objv = np.array([objv1, objv2]).T

    def cal_cv(self, pop: pg.Population) -> None:
        t = pop.objv[:, 1] + np.sqrt(pop.objv[:, 0]) - np.sin(
            2 * np.pi * np.sqrt(pop.objv[:, 0]) - pop.objv[:, 1] + 1) - 1
        pop.cv = (-t / (1 + np.exp(4 * np.abs(t)))).reshape(-1, 1)

    def get_optimal(self) -> np.ndarray:
        raise NotImplemented("get optimal has not been implemented")